package pri.zxx.word;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.CollectionUtils;
import pri.zxx.word.dat.*;
import pri.zxx.word.util.WordUtil;
import pri.zxx.word.util.XPBuilder;

import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Slf4j
public class TestReporter extends AbstractPoiWordTemplate<WordData> {

    private static int defaultTitleWP = 18;
    @Override
    public AbstractPoiWordTemplate<WordData> customStyle(WordData wordData) {
        return this;
    }

    @Override
    public AbstractPoiWordTemplate<WordData> headerFooter(WordData wordData) {
        ClassPathResource classPathResource = new ClassPathResource("files/img_logo_1.png");

        /* ***************************    header      **************************/

        XWPFHeader header1 = this.xwpfDocument.createHeader(HeaderFooterType.DEFAULT);

        XWPFParagraph paragraph1 = header1.createParagraph();
        paragraph1.setBorderBottom(Borders.SINGLE);
        paragraph1.setAlignment(ParagraphAlignment.RIGHT);

        XWPFRun r1 = paragraph1.createRun();

        XWPFPicture picture;
        try {
            picture = r1.addPicture(classPathResource.getInputStream(), XWPFDocument.PICTURE_TYPE_JPEG, "a.jpg", Units.toEMU(24), Units.toEMU(27));
        } catch (InvalidFormatException | IOException e) {
            log.error("添加页眉图标异常", e);
            throw new RuntimeException("添加页眉图标异常" + e.getMessage());
        }
        String blipID;
        for (XWPFPictureData picturedata : header1.getAllPackagePictures()) { // 这段必须有，不然打开的logo图片不显示
            blipID = header1.getRelationId(picturedata);
            picture.getCTPicture().getBlipFill().getBlip().setEmbed(blipID);
        }
        // 2. 获取到图片数据
        CTDrawing drawing = r1.getCTR().getDrawingArray(0);
        CTGraphicalObject graphicalobject = drawing.getInlineArray(0).getGraphic();

        //拿到新插入的图片替换添加CTAnchor 设置浮动属性 删除inline属性
        CTAnchor anchor = getAnchorWithGraphic(graphicalobject, "logo",
                Units.toEMU(25), Units.toEMU(27),//图片大小
                Units.toEMU(0), Units.toEMU(-18), false);//相对当前段落位置 需要计算段落已有内容的左偏移
        drawing.setAnchorArray(new CTAnchor[]{anchor});//添加浮动属性
        drawing.removeInline(0);//删除行内属性

        String animalType = wordData.getAnimalType();
        pTextPound(paragraph1, "饲料研究院" + animalType + "试验报告", false, 21);

        /* ***************************    footer      **************************/
        XWPFFooter footer = new XWPFHeaderFooterPolicy(xwpfDocument).createFooter(XWPFHeaderFooterPolicy.DEFAULT);
        XWPFParagraph fp = footer.createParagraph();
        fp.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun run;
        run = fp.createRun();
        run.setFontSize(10);
        run.setText("Page ");

        run = fp.createRun();
        run.setBold(true);
        run.getCTR().addNewFldChar().setFldCharType(org.openxmlformats.schemas.wordprocessingml.x2006.main.STFldCharType.BEGIN);

        run = fp.createRun();
        run.getCTR().addNewInstrText().setStringValue("PAGE \\* MERGEFORMAT");

        run = fp.createRun();
        run.setBold(true);
        run.getCTR().addNewFldChar().setFldCharType(org.openxmlformats.schemas.wordprocessingml.x2006.main.STFldCharType.END);

        run = fp.createRun();
        run.setText(" of ");
        run.setFontSize(10);


        run = fp.createRun();
        run.setBold(true);
        run.getCTR().addNewFldChar().setFldCharType(org.openxmlformats.schemas.wordprocessingml.x2006.main.STFldCharType.BEGIN);

        run = fp.createRun();
        run.setBold(true);
        run.getCTR().addNewInstrText().setStringValue("NUMPAGES \\* MERGEFORMAT");

        run = fp.createRun();
        run.setBold(true);
        run.getCTR().addNewFldChar().setFldCharType(org.openxmlformats.schemas.wordprocessingml.x2006.main.STFldCharType.END);

        return this;
    }

    public static CTAnchor getAnchorWithGraphic(CTGraphicalObject ctGraphicalObject,
                                                String deskFileName, int width, int height,
                                                int leftOffset, int topOffset, boolean behind) {
        String anchorXML =
                "<wp:anchor xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" "
                        + "simplePos=\"0\" relativeHeight=\"0\" behindDoc=\"" + ((behind) ? 1 : 0) + "\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">"
                        + "<wp:simplePos x=\"0\" y=\"0\"/>"
                        + "<wp:positionH relativeFrom=\"column\">"
                        + "<wp:posOffset>" + leftOffset + "</wp:posOffset>"
                        + "</wp:positionH>"
                        + "<wp:positionV relativeFrom=\"paragraph\">"
                        + "<wp:posOffset>" + topOffset + "</wp:posOffset>" +
                        "</wp:positionV>"
                        + "<wp:extent cx=\"" + width + "\" cy=\"" + height + "\"/>"
                        + "<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>"
                        + "<wp:wrapNone/>"
                        + "<wp:docPr id=\"1\" name=\"Drawing 0\" descr=\"" + deskFileName + "\"/><wp:cNvGraphicFramePr/>"
                        + "</wp:anchor>";

        CTDrawing drawing = null;
        try {
            drawing = CTDrawing.Factory.parse(anchorXML);
        } catch (XmlException e) {
            e.printStackTrace();
        }
        CTAnchor anchor = drawing.getAnchorArray(0);
        anchor.setGraphic(ctGraphicalObject);
        return anchor;
    }


    @Override
    public AbstractPoiWordTemplate<WordData> buildContext(WordData wordData) {
        /* ***************************  page1        **************************/

        WordBaseDataProperties wordBaseDataProperties = wordData.getWordBaseDataProperties();
        List<WordBaseDataProperties.SentenceInfo> sentenceInfoList = wordBaseDataProperties.getSentenceInfoList();
        if (CollectionUtils.isEmpty(sentenceInfoList)) {
            throw new RuntimeException("基础word内容未配置");
        }
        AtomicInteger tableNum = new AtomicInteger(1);
        sentenceInfoList
                .forEach(sentenceInfo -> {
                    List<WordBaseDataProperties.RunInfo> runInfos = sentenceInfo.getRunInfos();

                    XPBuilder p = XPBuilder.createP(xwpfDocument)
                            .overflowPunct(sentenceInfo.getOverFlowPunct())
                            .align(sentenceInfo.getParagraphAlignment(), sentenceInfo.getTextAlignment());

                    if (sentenceInfo.getLineSpace() != null && sentenceInfo.getStLineSpacingRule() != null) {
                        p.lineSpace(sentenceInfo.getLineSpace(), STLineSpacingRule.Enum.forInt(sentenceInfo.getStLineSpacingRule()));
                    }

                    if (sentenceInfo.getLineSpaceType() != null && sentenceInfo.getLineAfter() != null && sentenceInfo.getLineBefore() != null) {
                        LineSpaceType lineSpaceType = sentenceInfo.getLineSpaceType();
                        if (lineSpaceType == LineSpaceType.LINE) {
                            p.spaceInLine(sentenceInfo.getLineAfter(), sentenceInfo.getLineBefore());
                        } else {
                            p.spaceInPound(sentenceInfo.getLineAfter(), sentenceInfo.getLineBefore());
                        }
                    }

                    if (sentenceInfo.getIndentChart() != null) {
                        p.indentInChart(sentenceInfo.getIndentChart(), 0, 0, 0);
                    }

                    XWPFParagraph build = p.build();
                    build.setPageBreak(sentenceInfo.getPageBreak());
                    runInfos.forEach(runInfo -> {
                        String text = runInfo.getText();
                        text = replaceKey(wordData, text);
                        runInfo.setText(text);

                        if (runInfo.getFontSizeType() == FontSizeType.POUND) {
                            pTextPound(build, runInfo.getText(), runInfo.getBold(), runInfo.getFontSize());
                        } else {
                            pText(build, runInfo.getText(), runInfo.getBold(), runInfo.getFontSize());
                        }

                        if (runInfo.getReturnCount() > 0) {
                            IntStream.range(0, runInfo.getReturnCount()).forEach(value -> {
                                XWPFParagraph breakP = XPBuilder.createP(xwpfDocument)
                                        .copyStyle(build).build();

                                breakP.setAlignment(ParagraphAlignment.CENTER);
                                breakP.setWordWrapped(true);

                                XWPFRun run = breakP.createRun();
                                run.setText("\n");
                                run.setFontSize(runInfo.getFontSize());
                                breakP.setPageBreak(false);
                            });
                        }
                    });
                    TableType tableType = sentenceInfo.getTableType();

                    XWPFTable table;
                    List<XWPFTableRow> rows;
                    List<WordData.GroupInfo> groupInfos = wordData.getGroupInfos();
                    List<String> groupName = groupInfos.stream().map(WordData.GroupInfo::getGroupName).collect(Collectors.toList());
                    switch (tableType) {
                        case NONE:
                            break;
                        case GROUP_DATA:
                            tableTitle("表" + tableNum + "试验设计");
                            table = createDefaultTable(xwpfDocument, 1, groupInfos.size(), 2, 100, TableRowAlign.CENTER);
                            rows = table.getRows();
                            for (int i = 0; i < groupInfos.size(); i++) {
                                WordData.GroupInfo groupInfo = groupInfos.get(i);
                                XWPFTableRow xwpfTableRow = rows.get(i);
                                int j = 0;
                                XWPFTableCell cell = getCol(xwpfTableRow, j++, 20);
                                cell.setText(groupInfo.getGroupName());
                                XWPFTableCell cell1 = xwpfTableRow.getCell(j++);
                                cell1.setText(groupInfo.getDesc());
                            }
                            tableNum.getAndIncrement();
                            break;
                        case INPUT_DATA:
                            List<WordData.StageInfo> stageInfoList = wordData.getStageInfoList();
                            if (CollectionUtils.isEmpty(stageInfoList)) {
                                break;
                            }
                            stageInfoList.forEach(stageInfo -> {
                                tableTitle("表" + tableNum.getAndIncrement() + ". " + stageInfo.getStageName() + "（" + stageInfo.getStartDays() + "-" + stageInfo.getEndDays() + "）试验日粮配方组成");
                                List<WordData.SimpleTableInfo> rawInfos = stageInfo.getRawInfos();

                                Map<String, Map<Long, WordData.SimpleTableInfo>> rawGroupMap = rawInfos.stream().collect(Collectors.groupingBy(WordData.SimpleTableInfo::getName, Collectors.toMap(WordData.SimpleTableInfo::getGroupId, o -> o, (o1, o2) -> o2)));

                                XWPFTable rawTable = createDefaultTable(xwpfDocument, 1, rawGroupMap.size() + 1, groupInfos.size() + 1, 100, TableRowAlign.CENTER);
                                //title
                                tableHeader("原料", groupName, rawTable);

                                Set<String> strings = rawGroupMap.keySet();
                                AtomicInteger i = new AtomicInteger(1);
                                strings.forEach(s -> {
                                    XWPFTableRow row = getRow(rawTable, i.getAndIncrement());
                                    Map<Long, WordData.SimpleTableInfo> longListMap = rawGroupMap.get(s);
                                    XWPFTableCell cell = getCol(row, 0);
                                    handleTitle(s, cell);

                                    AtomicInteger j = new AtomicInteger(1);
                                    groupInfos.forEach(groupInfo -> {
                                        XWPFTableCell cell1 = getCol(row, j.getAndIncrement());
                                        String value = " - ";
                                        if (!CollectionUtils.isEmpty(longListMap)) {
                                            WordData.SimpleTableInfo simpleTableInfo = longListMap.get(groupInfo.getGroupId());
                                            if (simpleTableInfo != null) {
                                                value = String.valueOf(simpleTableInfo.getValue());
                                            }
                                        }
                                        cell1.setText(value);
                                    });
                                });


                                List<WordData.SimpleTableInfo> nutritionInfo = stageInfo.getNutritionInfo();

                                tableTitle("表" + tableNum.getAndIncrement() + ". " + stageInfo.getStageName() + "（" + stageInfo.getStartDays() + "-" + stageInfo.getEndDays() + "）试验日粮营养成分");

                                XWPFTable nutritionTable = createDefaultTable(xwpfDocument, 1, nutritionInfo.size(), groupInfos.size() + 1, 100, TableRowAlign.CENTER);
                                Map<String, Map<Long, WordData.SimpleTableInfo>> nutritionMap =
                                        nutritionInfo.stream().collect(Collectors.groupingBy(WordData.SimpleTableInfo::getName, Collectors.toMap(WordData.SimpleTableInfo::getGroupId, o -> o, (o1, o2) -> o2)));

                                //title
                                tableHeader("项目", groupName, nutritionTable);
                                Set<String> nutritionNames = nutritionMap.keySet();
                                AtomicInteger ni = new AtomicInteger(1);
                                nutritionNames.forEach(s -> {
                                    XWPFTableRow row = getRow(nutritionTable, ni.getAndIncrement());
                                    Map<Long, WordData.SimpleTableInfo> longListMap = nutritionMap.get(s);
                                    XWPFTableCell cell = getCol(row, 0);
                                    handleTitle(s, cell);
                                    AtomicInteger nj = new AtomicInteger(1);
                                    groupInfos.forEach(groupInfo -> {
                                        XWPFTableCell cell1 = getCol(row, nj.getAndIncrement());

                                        String value = " - ";
                                        if (!CollectionUtils.isEmpty(longListMap)) {
                                            WordData.SimpleTableInfo simpleTableInfo = longListMap.get(groupInfo.getGroupId());
                                            if (simpleTableInfo != null) {
                                                value = String.valueOf(simpleTableInfo.getValue());
                                            }
                                        }
                                        cell1.setText(value);
                                    });
                                });
                            });
                            break;
                        case OUT_PUT:
                            List<ExperimentResult> experimentResults = wordData.getExperimentResults();
                            if (!CollectionUtils.isEmpty(experimentResults)) {
                                Map<String, List<ExperimentResult>> resultMap = experimentResults.stream().collect(Collectors.groupingBy(ExperimentResult::getExpTypeName));

                                List<String> resultTableOrder = wordBaseDataProperties.getResultTableOrder();
                                AtomicInteger order = new AtomicInteger(1);
                                resultTableOrder.forEach(s -> {
                                    List<ExperimentResult> resultList = resultMap.get(s);
                                    if (!CollectionUtils.isEmpty(resultList)) {
                                        resultList.forEach(r -> {
                                            if (StringUtils.isEmpty(r.getStageName())) {
                                                r.setStageName("all");
                                            }
                                        });
                                        Map<String, Map<String, List<ExperimentResult>>> stageGroupMap = resultList.stream().collect(Collectors.groupingBy(ExperimentResult::getStageName, Collectors.groupingBy(ExperimentResult::getIndicator)));
                                        if (!CollectionUtils.isEmpty(stageGroupMap)) {
                                            title3("3." + order.getAndIncrement() + " xxx对" + wordData.getAnimalType() + s + "的影响");
                                            contentV("请补充试验结果。");
//                                            表9. xxx对{试验动物品种}免疫的影响
                                            tableTitle("表" + tableNum.intValue() + ". xxx对" + wordData.getAnimalType() + s + "的影响");
                                            boolean b = stageGroupMap.keySet().stream().allMatch("all"::equals);
                                            //title
                                            List<String> groupsNames = groupInfos.stream().map(WordData.GroupInfo::getGroupName).collect(Collectors.toList());
                                            groupsNames.add("CV%");
                                            groupsNames.add("P");
                                            XWPFTable resultTable;

                                            int rowNum;
                                            int colNum;

                                            if (b) {
                                                Map<String, List<ExperimentResult>> all = stageGroupMap.get("all");
                                                rowNum = all.keySet().size() + 1;
                                                colNum = groupInfos.size() + 3;
                                                resultTable = createDefaultTable(xwpfDocument, 1, rowNum, colNum, 100, TableRowAlign.CENTER);
                                                tableNum.getAndIncrement();
                                                //title
                                                tableHeader("项目（指标）", groupsNames, resultTable);
                                                AtomicInteger index = new AtomicInteger(1);
                                                all.forEach((s1, ex2) -> {
                                                    XWPFTableRow row = getRow(resultTable, index.getAndIncrement());
                                                    AtomicInteger cIndex = new AtomicInteger(0);
                                                    XWPFTableCell title = getCol(row, cIndex.getAndIncrement());
                                                    handleTitle(s1, title);

                                                    Map<String, Map<String, ExperimentResult>> groupNameIndecatorMap = ex2.stream().collect(Collectors.groupingBy(ExperimentResult::getGroupName, Collectors.toMap(ExperimentResult::getIndicator, o -> o, (o1, o2) -> o2)));
                                                    groupsNames.forEach(gName -> handleIndicator(groupNameIndecatorMap, gName, s1, row, cIndex));
                                                });

                                            } else {
                                                //有阶段
                                                int size = stageGroupMap.keySet().size();
                                                Integer indecatorCount = stageGroupMap.values().stream().map(Map::size).reduce(Integer::sum).orElse(0);

                                                rowNum = size + indecatorCount + 1;
                                                colNum = groupInfos.size() + 3;

                                                resultTable = createDefaultTable(xwpfDocument, 1, rowNum, colNum, 100, TableRowAlign.CENTER);
                                                tableNum.getAndIncrement();
                                                tableHeader("项目（指标）", groupsNames, resultTable);

                                                AtomicInteger rowIndex = new AtomicInteger(1);
                                                int hMergeCount = groupsNames.size() - 1;
                                                List<String> stagetList = wordData.getStageInfoList().stream().map(WordData.StageInfo::getStageName).sorted(String::compareTo).collect(Collectors.toList());
                                                stagetList.forEach(s1 -> {
                                                    Map<String, List<ExperimentResult>> stringListMap = stageGroupMap.get(s1);
                                                    //stage
                                                    XWPFTableRow row = getRow(resultTable, rowIndex.getAndIncrement());
                                                    XWPFTableCell stageTitle = getCol(row, 0);
                                                    handleTitle(s1, stageTitle);
                                                    mergeCellsHorizontal(resultTable, rowIndex.get() - 1, 0, hMergeCount);
                                                    //title
                                                    AtomicInteger cIndex = new AtomicInteger(0);
                                                    stringListMap.forEach((s2, ex1) -> {
                                                        XWPFTableRow title = getRow(resultTable, rowIndex.getAndIncrement());
                                                        XWPFTableCell cell = getCol(title, cIndex.getAndIncrement());
//                                                        handleTitle(s2, cell);
                                                        cell.setText(s2);
                                                        Map<String, Map<String, ExperimentResult>> groupNameIndecatorMap = ex1.stream().collect(Collectors.groupingBy(ExperimentResult::getGroupName, Collectors.toMap(ExperimentResult::getIndicator, o -> o, (o1, o2) -> o2)));
                                                        groupsNames.forEach(gName -> handleIndicator(groupNameIndecatorMap, gName, s2, title, cIndex));
                                                    });
                                                });
                                            }
                                        }
                                    }
                                });
                            }
                            break;
                        default:
                            throw new RuntimeException("位置表格类型");
                    }
                });

        return this;
    }

    public static void handleTitle(String s, XWPFTableCell cell) {
        cell.removeParagraph(0);
        XWPFParagraph paragraph = cell.addParagraph();
        XWPFRun run = paragraph.createRun();
        run.setBold(true);
        run.setText(s);
    }

    public static void handleIndicator(Map<String, Map<String, ExperimentResult>> groupNameIndecatorMap, String CV, String s1, XWPFTableRow row, AtomicInteger cIndex) {
        Map<String, ExperimentResult> indecatorMap = groupNameIndecatorMap.get(CV);
        ExperimentResult er = new ExperimentResult();
        if (indecatorMap != null) {
            er = Optional.ofNullable(indecatorMap.get(s1)).orElse(new ExperimentResult());
        }

        XWPFTableCell col = getCol(row, cIndex.getAndIncrement());
        XWPFParagraph paragraph = col.getParagraphArray(0);
        if (paragraph == null) {
            paragraph = col.addParagraph();
        }
        paragraph.setWordWrapped(true);
        paragraph.setAlignment(ParagraphAlignment.LEFT);
        paragraph.setVerticalAlignment(TextAlignment.CENTER);
        pTextPound(paragraph, Optional.ofNullable(er.getValue()).map(BigDecimal::toPlainString).orElse("") + Optional.ofNullable(er.getVariance()).map(bigDecimal -> "±" + bigDecimal.toPlainString()).orElse(""), false, 21);

        if (StringUtils.isNotEmpty(er.getSubscript())) {
            XWPFRun tip = paragraph.createRun();
            tip.setVerticalAlignment(STVerticalAlignRun.SUPERSCRIPT.toString());
            tip.setText(er.getSubscript());
        }
    }

    public static XWPFTableCell getCol(XWPFTableRow row, int cIndex) {
        return getCol(row, cIndex, true, defaultTitleWP);
    }

    public static XWPFTableCell getCol(XWPFTableRow row, int cIndex, int width) {
        return getCol(row, cIndex, true, width);
    }

    public static XWPFTableCell getCol(XWPFTableRow row, int cIndex, boolean bold, int width) {
        List<XWPFTableCell> tableCells = row.getTableCells();
        int size = tableCells.size();
        int i = 100 - width;
        float i1 = i / (size - 1);

        XWPFTableCell cell = row.getCell(cIndex);
        if (cell == null) {
            cell = row.createCell();
        }
        if (cIndex == 0) {
            cell.setWidth(width + "%");
            if (bold) {
                setTableFontStyle(cell);
            }
        } else {
            cell.setWidth(i1 + "%");
        }
        return cell;
    }

    public static void setTableFontStyle(XWPFTableCell cell) {
        List<XWPFParagraph> paragraphs = cell.getParagraphs();
        if (!CollectionUtils.isEmpty(paragraphs)) {
            paragraphs.forEach(paragraph -> {
                List<XWPFRun> runs = paragraph.getRuns();
                if (!CollectionUtils.isEmpty(runs)) {
                    runs.forEach(xwpfRun -> xwpfRun.setBold(true));
                }
            });
        }
    }

    public static XWPFTableRow getRow(XWPFTable resultTable, int index) {
        XWPFTableRow row = resultTable.getRow(index);
        if (row == null) {
            row = resultTable.createRow();
        }
        return row;
    }

    public static void tableHeader(String key, List<String> titles, XWPFTable table) {
        tableHeader(key, titles, table, defaultTitleWP);
    }

    public static void tableHeader(String key, List<String> titles, XWPFTable table, int width) {
        List<XWPFTableCell> tableCells = table.getRow(0).getTableCells();
        int size = tableCells.size();
        float i1 = (100 - width) / (size - 1);

        for (int i = 0; i < tableCells.size(); i++) {
            XWPFTableCell xwpfTableCell = tableCells.get(i);
            if (i == 0) {
                xwpfTableCell.setText(key);
                xwpfTableCell.setWidth(width + "%");
                handleTitle(key, xwpfTableCell);
            } else {
                String titleName = titles.get(i - 1);
                xwpfTableCell.setWidth(i1 + "%");
                xwpfTableCell.setText(titleName);
                handleTitle(titleName, xwpfTableCell);
            }

        }
    }

    private String replaceKey(WordData wordData, String text) {
        if (StringUtils.isNotEmpty(text)) {
            Set<String> pares = WordUtil.pares(text);
            if (!CollectionUtils.isEmpty(pares)) {
                for (String s : pares) {
                    Map<String, Field> stringFieldMap = WordUtil.fieldMap(wordData);
                    Field field = stringFieldMap.get(s);
                    if (field != null) {
                        field.setAccessible(true);
                        Object o = null;
                        try {
                            o = field.get(wordData);

                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                        String value = "";
                        if (o != null) {
                            if (o instanceof List) {
                                List<Object> oList = (List<Object>) o;
                                value = oList.stream().filter(Objects::nonNull).map(Objects::toString)
                                        .collect(Collectors.joining("，"));
                            } else {
                                value = o.toString();
                            }
                        }
                        text = text.replace(s, value);
                    }
                }
            }
        }
        return text;
    }


    /**
     * 创建通用表格
     */
    public static XWPFTable createDefaultTable(XWPFDocument xwpfDocument, int titleCount, int row, int col, int widthPercentage, TableRowAlign rowAlign) {
        if (titleCount < 1) {
            throw new RuntimeException("标题行不能小于1");
        }
        XWPFTable table = xwpfDocument.createTable(row, col);
        table.setWidth(widthPercentage + "%");
        table.setTableAlignment(rowAlign);

        CTTblPr tblPr = table.getCTTbl().getTblPr();

        CTTblBorders ctTblBorders = tblPr.addNewTblBorders();
        CTBorder ctBorder = ctTblBorders.addNewTop();
        ctBorder.setSz(BigInteger.valueOf(12));
        ctBorder.setColor("006600");
        ctBorder.setVal(STBorder.SINGLE);
        CTBorder ctBorder2 = ctTblBorders.addNewBottom();

        ctBorder2.setSz(BigInteger.valueOf(12));
        ctBorder2.setColor("006600");
        ctBorder2.setVal(STBorder.SINGLE);

        CTTblLayoutType type = table.getCTTbl().getTblPr().addNewTblLayout();
        type.setType(STTblLayoutType.FIXED);

        for (int i = 0; i < row; i++) {
            XWPFTableRow r = table.getRow(i);
            if (r == null) {
                r = table.createRow();
            }
            r.setCantSplitRow(false);
            r.setHeight(350);
            for (int j = 0; j < col; j++) {
                XWPFTableCell c = getCol(r, j);

                CTTc ctTc = c.getCTTc();
                CTTcPr tcpr = ctTc.addNewTcPr();
                //                c.setWidth("auto");
                c.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
//                List<CTP> pList = ctTc.getPList();
//                pList.forEach(ctp -> ctp.addNewPPr().addNewJc().setVal(STJc.LEFT));

                CTTcBorders cb = tcpr.addNewTcBorders();
                CTBorder c1 = cb.addNewLeft();
                c1.setVal(STBorder.NIL);
                CTBorder c2 = cb.addNewRight();
                c2.setVal(STBorder.NIL);
                if (i > titleCount) {
                    CTBorder c4 = cb.addNewTop();
                    c4.setVal(STBorder.NIL);
                }

                if (i >= titleCount && i < row - 1) {
                    CTBorder c3 = cb.addNewBottom();
                    c3.setVal(STBorder.NIL);
                }
            }
        }
        return table;
    }

    public void tableTitle(String tableTitle) {
        tableTitle(tableTitle, false);
    }

    public void tableTitle(String tableTitle, boolean pageBreak) {
        XWPFParagraph tbt = XPBuilder.createP(xwpfDocument).lineSpace(1.5, STLineSpacingRule.AUTO)
                .align(ParagraphAlignment.CENTER, TextAlignment.CENTER).build();
        pTextPound(tbt, tableTitle, true, 21);
        if (pageBreak) {
            tbt.setPageBreak(true);
        }
    }

    public void title3(String t3) {
        title(t3, false, false);
    }

    public void title(String text, boolean bold, boolean pageBreak) {
        XWPFParagraph tp1 = XPBuilder.createP(xwpfDocument)
                .lineSpace(1.5, STLineSpacingRule.AUTO).build();
        pText(tp1, text, bold, 12);
        if (pageBreak) {
            tp1.setPageBreak(true);
        }
    }

    public void contentV(String txt, boolean pageBreak) {
        XWPFParagraph text = XPBuilder.createP(xwpfDocument).overflowPunct(false).lineSpace(1.5, STLineSpacingRule.AUTO).indentInChart(2, 0, 0, 0).build();
        pText(text, txt, false, 12);
        if (pageBreak) {
            text.setPageBreak(pageBreak);
        }
    }

    public void contentV(String txt) {
        contentV(txt, false);
    }

}
